
uniform highp vec4  g_DisFogColor;
uniform highp vec4  g_HeightFogColor;
uniform highp vec4  g_FogParam;
uniform highp vec4  g_Eye;
uniform highp float g_Time;
uniform highp vec4  g_color_alpha;


uniform highp vec4 g_AmbientLight;
uniform highp vec4 g_BoneTM[180];
//uniform DirLight g_Dirlight[2];

uniform highp vec4 g_Dirlight[6];


uniform highp vec4 g_Pointlight[48];


uniform highp mat4 g_WorldViewProj;
uniform highp mat4 g_WorldView;

uniform sampler2D g_Shadowmap;
uniform highp mat4 g_ProjectMatrix;
uniform highp float g_ShadowDensity;

uniform sampler2D g_RandomRotationMap;
uniform highp vec4 g_RandomRotationMapUVScale;

#ifdef VS

attribute vec3 vPos;
attribute vec4 blendweights; 
attribute vec4 blendindices;
attribute vec3 vNormal;
attribute vec2 vTexCoord0;
attribute vec2 vTexCoord1;
attribute vec3 vTangent;
attribute vec3 vBinormal;
attribute vec4 vColor;

#endif


highp vec3 RotateVector(highp vec4 q,highp vec3 v)
{
	highp vec3 result;
	highp float x1 = q.y * v.z - q.z * v.y;
	highp float y1 = q.z * v.x - q.x * v.z;
	highp float z1 = q.x * v.y - q.y * v.x;
	highp float x2 = q.w * x1 + q.y * z1 - q.z * y1;
	highp float y2 = q.w * y1 + q.z * x1 - q.x * z1;
	highp float z2 = q.w * z1 + q.x * y1 - q.y * x1;
	result.x = v.x + 2.0 * x2;
	result.y = v.y + 2.0 * y2;
	result.z = v.z + 2.0 * z2;
	return result;
}

#ifdef  SKIN_MAXINFL

void DoSkinVertex(highp vec4 blendindices, highp vec4 blendweights, 
                  in highp vec4 vPos,in highp vec3 vNormal,
				  out highp vec3 pos,out highp vec3 normal)
{
	int indices[4];
	indices[0] = int(blendindices.x);
	indices[1] = int(blendindices.y);
	indices[2] = int(blendindices.z);
	indices[3] = int(blendindices.w);
	highp float weights[4];
	weights[0] = blendweights.x/255.0;
	weights[1] = blendweights.y/255.0;
	weights[2] = blendweights.z/255.0;
	weights[3] = blendweights.w/255.0;
	
	pos = vec3(0, 0, 0);
	normal = vec3(0,0,0);

	for(int i=0; i<SKIN_MAXINFL; i++)
	{
		int offset = indices[i]*2;	
		highp vec3 rotpos = RotateVector(g_BoneTM[offset],vPos.xyz);
		pos +=	(rotpos + g_BoneTM[offset+1].xyz) * weights[i];
		highp vec3 rotnormal = RotateVector( g_BoneTM[offset], vNormal );
		normal += rotnormal * weights[i];
	}
	
}

void DoSkinVertexTBN(highp vec4 blendindices, highp vec4 blendweights, 
				  in highp vec4 vPos,in highp vec3 vNormal,in highp vec3 vTangent,in highp vec3 vBiNormal,
				  out highp vec3 pos,out highp vec3 normal,out highp vec3 tangent,out highp vec3 binormal)
{
	int indices[4];
	indices[0] = int(blendindices.x);
	indices[1] = int(blendindices.y);
	indices[2] = int(blendindices.z);
	indices[3] = int(blendindices.w);
	highp float weights[4];
	weights[0] = blendweights.x/255.0;		//100
	weights[1] = blendweights.y/255.0;
	weights[2] = blendweights.z/255.0;
	weights[3] = blendweights.w/255.0;
	
	pos = vec3(0, 0, 0);
	normal = vec3(0,0,0);
	tangent = vec3(0,0,0);
	binormal = vec3(0,0,0);

	for(int i=0; i<SKIN_MAXINFL; i++)
	{
		int offset = indices[i] * 2;	
		highp vec3 rotpos = RotateVector(g_BoneTM[offset],vPos.xyz);
		pos +=	(rotpos + g_BoneTM[offset+1].xyz) * weights[i];
		highp vec3 rotnormal = RotateVector( g_BoneTM[offset], vNormal );
		normal += rotnormal * weights[i];
		highp vec3 rottangent = RotateVector( g_BoneTM[offset], vTangent );
		tangent += rottangent * weights[i];
		highp vec3 rotbinormal = RotateVector( g_BoneTM[offset], vBiNormal );
		binormal += rotbinormal * weights[i];
	}
	
}

#endif


highp float CalculateSpecular(highp vec3 normal, highp vec3 lightDir, highp vec3 viewDir, highp float glossiness )
{
	highp vec3 halfway = normalize( lightDir + viewDir );

	highp float NdotL = max( dot( normal, lightDir ), 0.0 );
	highp float NdotH = max( dot( normal, halfway ), 0.0 );

	return (glossiness + 2.0) / 8.0 * pow( NdotH, glossiness ) * NdotL;
}


struct DirLight
{
	highp vec4 lightDir;
	highp vec4 lightColor;
	highp vec4 ambient;
};

highp vec3 DirLightFunc( DirLight dirLight, highp vec3 pos, highp vec3 normal, highp vec4 modelEyePos, highp float glossiness)
{
	//dirLight.lightDir.xyz = normalize(vec3(2.0, 4.0, 6.0));   //only for test
	highp vec3 viewVec = modelEyePos.xyz - pos;
	highp vec3 viewDir = normalize(viewVec);
	
	highp vec3 diffuse = dirLight.lightColor.xyz * max( dot( normal, dirLight.lightDir.xyz ), 0.0 ) ;
	//diffuse *= texture2D(g_DiffuseTex, tex ).xyz;
	highp float specular = CalculateSpecular( normal, dirLight.lightDir.xyz, viewDir, glossiness);
	//specular *= texture(g_SpecularTex, tex).xyz * g_SpecPower;
	return  diffuse + specular;
}


struct PointLight
{
	highp vec4 lightPos;
	highp vec4 lightColor;
	highp vec4 PointLightColorAttenuation;
    highp vec4 ambient;
};

highp vec3 PointLightFunc(PointLight pointLight, highp vec3 pos, highp vec3 normal, highp vec4 modelEyePos, highp float glossiness)
{
	highp vec3 lightVec = pointLight.lightPos.xyz - pos;
	highp vec3 lightDir = normalize(lightVec);

	highp vec3 viewVec = modelEyePos.xyz - pos;
	highp vec3 viewDir = normalize(viewVec);
	
	highp float lightDist = length(lightVec);   
	highp float lightRatio = max(1.0 - lightDist / pointLight.lightPos.w, 0.0);
	highp float falloff = pow(lightRatio, pointLight.PointLightColorAttenuation.w);     //adapt  PointLightColorAttenuation

	highp vec3 diffuse = pointLight.PointLightColorAttenuation.xyz * max( dot( normal, lightDir ), 0.0 ) /** falloff*/;    //adapt  PointLightColorAttenuation, g_AmbientLight
	//diffuse *= texture2D(g_DiffuseTex, tex ).xyz;
	highp float specular = CalculateSpecular( normal, lightDir, viewDir, glossiness);
	//specular *= texture(g_SpecularTex, tex).xyz * g_SpecPower;
	
	return (diffuse + specular)*falloff;
}


highp vec3 CaculateLight(highp vec3 modelpos,highp vec3 normal,highp float Dirvisiblity)
{
	highp vec3 light = g_AmbientLight.xyz;
	highp float glossiness = 1.0;

#ifdef  NUM_DIRLIGHT 
	for(int i=0;i<NUM_DIRLIGHT;i++)
	{
		DirLight dL;
		dL.lightDir = g_Dirlight[2*i];
		dL.lightColor = g_Dirlight[2*i+1];
		highp vec4 g_modelEyePos = g_Eye;
		//float glossiness = 30.0;
		light += Dirvisiblity * DirLightFunc(dL, modelpos, normal, g_modelEyePos, glossiness);
		//light += Dirvisiblity * DirLightFunc(g_Dirlight[2*i],g_Dirlight[2*i+1],normal);
	}
#endif

#ifdef NUM_POINTLIGHT 
	for(int i=0;i<NUM_POINTLIGHT;i++)
	{
		PointLight pL;
		pL.lightPos = g_Pointlight[3*i];
		pL.lightColor = g_Pointlight[3*i+1];
		pL.PointLightColorAttenuation = vec4(pL.lightColor.xyz, 0.8);
		highp vec4 modelEyePos = g_Eye;
		//float glossiness = 30.0;
		light += Dirvisiblity * PointLightFunc(pL, modelpos, normal, modelEyePos, glossiness);
		//light += PointLightFunc(g_Pointlight[2*i], g_Pointlight[2*i+1],modelpos, normal);
	}
#endif

	return light;
}


void DirLightFuncSp(in DirLight dirLight, highp vec3 pos, highp vec3 normal, in highp vec4 modelEyePos, in highp float glossiness, out highp vec3 diffuse, out highp float specular)
{
	//dirLight.lightDir.xyz = normalize(vec3(2.0, 4.0, 6.0));   //only for test
	highp vec3 viewVec = modelEyePos.xyz - pos;
	highp vec3 viewDir = normalize(viewVec);
	
	diffuse = dirLight.lightColor.xyz * max( dot( normal, dirLight.lightDir.xyz ), 0.0 ) + dirLight.ambient.xyz;
	specular = CalculateSpecular( normal, dirLight.lightDir.xyz, viewDir, glossiness );
}

void PointLightFuncSp(in PointLight pointLight, in highp vec3 pos, in highp vec3 normal, in highp vec4 modelEyePos, in highp float glossiness, out highp vec3 diffuse, out highp float specular)
{
	highp vec3 lightVec = pointLight.lightPos.xyz - pos;
	highp vec3 lightDir = normalize(lightVec);

	highp vec3 viewVec = modelEyePos.xyz - pos;
	highp vec3 viewDir = normalize(viewVec);
	
	highp float lightDist = length(lightVec);   
	highp float lightRatio = max(1.0 - lightDist / pointLight.lightPos.w, 0.0);
	highp float falloff = pow(lightRatio, pointLight.PointLightColorAttenuation.w);     //adapt  PointLightColorAttenuation

	diffuse = pointLight.PointLightColorAttenuation.xyz * max( dot( normal, lightDir ), 0.0 ) + pointLight.ambient.xyz;    //adapt  PointLightColorAttenuation, g_AmbientLight
	diffuse *= falloff;

	specular = CalculateSpecular( normal, lightDir, viewDir, glossiness);
	specular *= falloff;
}

#ifdef PS

highp vec2 Rotate2D(highp float sin_t, highp float cos_t, highp vec2 v)
{
    highp mat2 m;
    m[0] = vec2(cos_t, -sin_t);
    m[1] = vec2(sin_t, cos_t);
    return m * v;
}

highp float GetShadowSample(sampler2D shadowmap, highp float depth, highp vec2 shadowUV, highp vec2 sintcost, highp float radius, highp vec2 poisson)
{
    highp vec2 offset = Rotate2D(sintcost.x, sintcost.y, poisson) * radius;
    return depth > texture2D( shadowmap, shadowUV + offset ).x  ? 0.0 : 1.0;
}

highp float ShadowPCF8x(sampler2D shadowmap, highp vec4 shadowUV, highp float radius)
{
    highp float shadow = 0.0;
    highp vec2  screenUV = gl_FragCoord.xy * g_RandomRotationMapUVScale.xy;
    highp vec2  sintcost = texture2D( g_RandomRotationMap, screenUV ).rg;
    highp float depth = min(shadowUV.z/shadowUV.w - 1e-2, 1.0);
    sintcost = sintcost * 2.0 - 1.0;
    radius *= 0.015;

    shadow += GetShadowSample(shadowmap, depth, shadowUV.xy, sintcost, radius, vec2(-0.8067961, -0.1735136));
    shadow += GetShadowSample(shadowmap, depth, shadowUV.xy, sintcost, radius, vec2(-0.1160412, -0.3263741));
    shadow += GetShadowSample(shadowmap, depth, shadowUV.xy, sintcost, radius, vec2(0.2745395, 0.1202338));
    shadow += GetShadowSample(shadowmap, depth, shadowUV.xy, sintcost, radius, vec2(-0.531391, 0.512445));
    shadow += GetShadowSample(shadowmap, depth, shadowUV.xy, sintcost, radius, vec2(0.3538843, -0.8416352));
    shadow += GetShadowSample(shadowmap, depth, shadowUV.xy, sintcost, radius, vec2(0.8273658, -0.1064943));
    shadow += GetShadowSample(shadowmap, depth, shadowUV.xy, sintcost, radius, vec2(0.359133, 0.8904359));
    shadow += GetShadowSample(shadowmap, depth, shadowUV.xy, sintcost, radius, vec2(-0.4294311, -0.8222));

    shadow *= 0.125;
    return shadow;
}

#endif

//vec3 CalculateLightSp(vec3 modelpos,vec3 normal,float Dirvisiblity, float g_SpecGlossy, float g_SpecPower, sampler2D g_SpecularTex, sampler2D g_DiffuseTex, float g_DiffusePow, vec2 tex)
void CalculateLightSp(in highp vec3 modelpos, in highp vec3 normal, in highp float Dirvisiblity, in highp float g_SpecGlossy, out highp vec3 diffuse, out highp float specular)
{
	normal = normalize(normal);	
	DirLight dL;
	PointLight pL;
	highp vec4 modelEyePos = g_Eye;
	highp float glossiness = g_SpecGlossy;

	/*vec3*/ diffuse = vec3(0.0, 0.0, 0.0);
	/*float*/ specular = 0.0;

#ifdef NUM_DIRLIGHT 
	for(int i=0;i<NUM_DIRLIGHT;i++)
	{		
		dL.lightDir = g_Dirlight[3*i];
		dL.lightColor = g_Dirlight[3*i+1];
		dL.ambient = g_Dirlight[3*i+2];
		
		highp vec3 diffuseTmp;
		highp float specularTmp;
		DirLightFuncSp(dL, modelpos, normal, modelEyePos, glossiness, diffuseTmp, specularTmp);
		diffuse += diffuseTmp * Dirvisiblity;
		specular += specularTmp * Dirvisiblity;
	}
#endif
#ifdef NUM_POINTLIGHT	
	for(int i=0;i<NUM_POINTLIGHT;i++)
		{
			pL.lightPos = g_Pointlight[3*i];
			pL.lightColor = g_Pointlight[3*i+1];
            pL.ambient = g_Pointlight[3*i+2];
			pL.PointLightColorAttenuation = pL.lightColor/*vec4(pL.lightColor.xyz, 1.0)*/;

			highp vec3 diffuseTmp;
			highp float specularTmp;
			PointLightFuncSp(pL, modelpos, normal, modelEyePos, glossiness, diffuseTmp, specularTmp);
			diffuse += diffuseTmp;
			specular += specularTmp;
		}	
#endif

}
